package com.abcode.nettyserversocketio.exception;

import com.abcode.nettyserversocketio.common.Result;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fasterxml.jackson.databind.JsonMappingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.thymeleaf.util.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandle {

    //<editor-fold desc="控制层参数校验失败异常处理">

    /**
     * 缺少参数抛出的异常是MissingServletRequestParameterException (参数使用了注解 @RequestParam)
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result missingParameterException(MissingServletRequestParameterException e) {
        log.error("|missingParameterException|", e);
        String msg = MessageFormat.format("缺少参数：{0}", e.getParameterName());
        Result result = Result.error(msg);
        return result;
    }

    /**
     * 单参数校验失败后抛出的异常是ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result constraintViolationException(ConstraintViolationException e) {
        log.error("|constraintViolationException|", e);
        Set<ConstraintViolation<?>> sets = e.getConstraintViolations();
        if (CollectionUtils.isNotEmpty(sets)) {
            StringBuilder sb = new StringBuilder();
            sets.forEach(error -> {
                if (error instanceof FieldError) {
                    sb.append(((FieldError) error).getField()).append(":");
                }
                sb.append(error.getMessage()).append(";");
            });
            String msg = sb.toString();
            msg = StringUtils.substring(msg, 0, msg.length() - 1);
            Result result = Result.error(msg);
            return result;
        } else {
            return Result.error(e.getMessage());
        }
    }

    /**
     * 请求的对象参数校验失败后抛出的异常是BindException
     */
    @ExceptionHandler(BindException.class)
    public Result bindException(BindException e) {
        log.error("|bindException|", e);
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        if (CollectionUtils.isNotEmpty(errors)) {
            StringBuilder sb = new StringBuilder();
            errors.forEach(error -> {
                if (error instanceof FieldError) {
                    sb.append(((FieldError) error).getField()).append(":");
                }
                sb.append(error.getDefaultMessage()).append(";");
            });
            String msg = sb.toString();
            msg = StringUtils.substring(msg, 0, msg.length() - 1);
            Result result = Result.error(msg);
            return result;
        }
        return Result.error(e.getMessage());
    }

    /**
     * 参数转对象失败会报的异常（一般是属性格式不对导致json转obj失败）
     *
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageConversionException.class)
    public Result notReadableException(HttpMessageConversionException e) {
        log.error("|notReadableException|", e);
        if (e.getCause() != null && (e.getCause() instanceof JsonMappingException)) {
            JsonMappingException invalidFormatException = (JsonMappingException) e.getCause();
            List<JsonMappingException.Reference> errorList = invalidFormatException.getPath();
            StringBuilder sb = new StringBuilder();
            errorList.forEach(item->{
                sb.append("属性：" + item.getFieldName()+ "的值格式不正确；");
            });
            return Result.error(sb.toString());
        } else {
            return Result.error(e.getMessage());
        }
    }

    //</editor-fold>

    @ExceptionHandler(Exception.class)
    public Result exception(Exception e) {
        log.error("|notReadableException|", e);
        return Result.error("服务器处理请求发生异常");
    }

    private String getValidExceptionMsg(List<ObjectError> errors) {
        if (CollectionUtils.isNotEmpty(errors)) {
            StringBuilder sb = new StringBuilder();
            errors.forEach(error -> {
                if (error instanceof FieldError) {
                    sb.append(((FieldError) error).getField()).append(":");
                }
                sb.append(error.getDefaultMessage()).append(";");
            });
            String msg = sb.toString();
            msg = StringUtils.substring(msg, 0, msg.length() - 1);
            return msg;
        }
        return null;
    }
}
